package com.n9.db.util;

import org.hibernate.Session;
import org.hibernate.query.Query;

import java.io.Serializable;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * 通用service
 * @author ice
 */
public class GenericService {

    /**
     * 根据ID查询对象
     * @param clazz
     * @param id
     * @param <E>
     * @return
     * @throws DbException
     */
    public <E> E get(Class<E> clazz, Serializable id) throws DbException {
        Session session = null;
        try {
            session = DbUtils.openSession();
            return session.get(clazz, id);
        } catch (Exception e) {
            throw new DbException(e.getMessage());
        } finally {
            DbUtils.close(session);
        }
    }

    /**
     * 通过hql查询
     * @param hql
     * @param <E>
     * @return
     * @throws DbException
     */
    public <E> E getByHql(String hql) throws DbException {
        ResultConverter<E> converter = (o) -> (E)o;
        return getByHql(hql, converter);
    }

    /**
     * 查询数量
     * @param hql
     * @return
     * @throws DbException
     */
    public long count(String hql) throws DbException {
        Long result = getByHql(hql, ResultConverter.LONG_CONVERTER);
        return Objects.isNull(result) ? 0L : result;
    }


    /**
     * hql查询
     * @param hql
     * @param converter
     * @param <E>
     * @return
     */
    public <E> E getByHql(String hql, ResultConverter<E> converter) {
        Session session = null;
        try {
            session = DbUtils.openSession();
            Query query = session.createQuery(hql);
            query.setMaxResults(1);
            query.setFirstResult(0);
            List list = query.list();

            if (Objects.isNull(list) || list.isEmpty()) {
                return null;
            }
            return converter.convert(list.get(0));
        } catch (Exception e) {
            throw new DbException(e.getMessage());
        } finally {
            DbUtils.close(session);
        }
    }

    /**
     * 分页查询
     * @param hql
     * @param converter
     * @param firstResult
     * @param maxResults
     * @param <E>
     * @return
     */
    public <E> List<E> query(String hql, ResultConverter<E> converter, int firstResult, int maxResults) {
        List<E> ret = new ArrayList<>(0);

        Session session = null;
        try {

            session = DbUtils.openSession();
            Query query = session.createQuery(hql);
            if (maxResults > 0) {
                query.setFirstResult(firstResult);
                query.setMaxResults(maxResults);
            }
            List list = query.list();

            list.forEach((o)-> ret.add(converter.convert(o)));
            return ret;
        } catch (Exception e) {
            throw new DbException(e.getMessage());
        } finally {
            DbUtils.close(session);
        }
    }

    /**
     * hql查询
     * @param hql
     * @param converter
     * @param <E>
     * @return
     */
    public <E> List<E> queryAll(String hql, ResultConverter<E> converter) {
        return query(hql, converter, 0, -1);
    }

    /**
     * hql查询
     * @param hql
     * @param <E>
     * @return
     */
    public <E> List<E> queryAll(String hql) {
        ResultConverter<E> converter = (o) -> (E)o;
        return queryAll(hql, converter);
    }


    //---------------------------------需要事务的操作----------------------------------------//

    /**
     * 保存对象
     * @param entity
     * @throws DbException
     */
    public void save(Object entity) throws DbException {
        execUpdate((session) -> session.save(entity));
    }

    /**
     * 批量保存
     * @param list
     * @throws DbException
     */
    public void saveBatch(Collection<?> list) throws DbException {
        execUpdate((session) -> {
            for (Object entity : list) {
                session.save(entity);
            }
        });
    }


    /**
     * 更新对象
     * @param entity
     * @throws DbException
     */
    public void update(Object entity) throws DbException {
        execUpdate((session) -> session.update(entity));
    }

    /**
     * 删除数据
     * @param id
     * @throws DbException
     */
    public void delete(String id) throws DbException {
        execUpdate((session) -> session.delete(id));
    }


    /**
     * 执行hql语句
     * @param hql
     * @throws DbException
     */
    public void execHql(String hql) throws DbException {
        execUpdate((session) -> {
            Query query = session.createQuery(hql);
            query.executeUpdate();
        });
    }

    /**
     * 批量执行hql
     * @param hqls
     * @throws DbException
     */
    public void execHql(List<String> hqls) throws DbException {
        execUpdate((session) -> {
            for (String hql : hqls) {
                Query query = session.createQuery(hql);
                query.executeUpdate();
            }
        });
    }

    /**
     * 执行修改
     * @param updateAction
     */
    public void execUpdate(UpdateAction updateAction) {
        Session session = null;
        try {
            session = DbUtils.openSession();
            DbUtils.begin(session);
            updateAction.execUpdate(session);
            DbUtils.commit(session);
        } catch (Exception e) {
            DbUtils.rollback(session);
            throw new DbException(e.getMessage());
        } finally {
            DbUtils.close(session);
        }
    }

    /**
     * 执行sql更新
     * @param sql
     */
    public void execSqlUpdate(String sql) {
        Session session = null;
        try {
            session = DbUtils.openSession();
            session.doWork(connection->{
                Statement statement = null;
                try {
                    connection.setAutoCommit(true);
                    statement= connection.createStatement();
                    statement.executeUpdate(sql);
                } finally {
                    DbUtils.close(statement);
                    DbUtils.close(connection);
                }
            });
        } catch (Exception e) {
            throw new DbException(e.getMessage());
        } finally {
            DbUtils.close(session);
        }
    }
}
